﻿namespace AddressBook.Business.Contact
{
	#region "Using Statements"
	using System;
	using System.Collections.Generic;
	using System.Linq;
	using System.Text;

	using Csla;
	using Csla.Data;
	using Csla.Validation;

	using AddressBook.Business.Person;
	#endregion

	[Serializable]
	public class ContactAddress : BusinessBase<ContactAddress>, IAddress
	{
		#region "Business Methods"

		#region "Private Static Member Variables"

		private static PropertyInfo<Int32> AddressIdProperty = RegisterProperty<Int32>(a => a.AddressId);
		private static PropertyInfo<Int32> ContactIdProperty = RegisterProperty<Int32>(a => a.ContactId);
		private static PropertyInfo<String> Address1Property = RegisterProperty<String>(a => a.Address1);
		private static PropertyInfo<String> Address2Property = RegisterProperty<String>(a => a.Address2);
		private static PropertyInfo<String> CityProperty = RegisterProperty<String>(a => a.City);
		private static PropertyInfo<Int32> StateProvinceIdProperty = RegisterProperty<Int32>(a => a.StateProvinceId);
		private static PropertyInfo<String> PostalCodeProperty = RegisterProperty<String>(a => a.PostalCode);
		private static PropertyInfo<SmartDate> ModifiedDateProperty = RegisterProperty<SmartDate>(a => a.ModifiedDate);
		private static PropertyInfo<Int32> AddressTypeIdProperty = RegisterProperty<Int32>(a => a.AddressTypeId);

		#endregion

		#region "Public Properties"

		public Int32 AddressId
		{
			get { return GetProperty(AddressIdProperty); }
			internal set { LoadProperty(AddressIdProperty, value); }
		}

		public Int32 ContactId
		{
			get { return GetProperty(ContactIdProperty); }
			internal set { LoadProperty(ContactIdProperty, value); }
		}

		public String Address1
		{
			get { return GetProperty(Address1Property); }
			set { SetProperty(Address1Property, value); }
		}

		public String Address2
		{
			get { return GetProperty(Address2Property); }
			set { SetProperty(Address2Property, value); }
		}

		public String City
		{
			get { return GetProperty(CityProperty); }
			set { SetProperty(CityProperty, value); }
		}

		public Int32 StateProvinceId
		{
			get { return GetProperty(StateProvinceIdProperty); }
			set { SetProperty(StateProvinceIdProperty, value); }
		}

		public String PostalCode
		{
			get { return GetProperty(PostalCodeProperty); }
			set { SetProperty(PostalCodeProperty, value); }
		}

		public Int32 AddressTypeId
		{
			get { return GetProperty(AddressTypeIdProperty); }
			set { SetProperty(AddressTypeIdProperty, value); }
		}

		public String ModifiedDate
		{
			get { return GetProperty(ModifiedDateProperty).ToString(); }
		}

		public String FullAddress
		{
			get
			{
				using (var ctx = ContextManager<AddressBook.Business.Model.AddressBookDataContext>.GetManager(AddressBook.Business.Model.Database.AddressBook))
				{
					AddressBook.Business.Model.StateProvince stateProvince = ctx.DataContext.StateProvinces.First(sp => sp.Id == this.StateProvinceId);

					if (String.IsNullOrEmpty(this.Address2))
					{
						return String.Format("{0} {1}, {2} {3}", this.Address1, this.City, stateProvince.StateProvinceCode, this.PostalCode);
					}

					return String.Format("{0} {1} {2}, {3} {4}", this.Address1, this.Address2, this.City, stateProvince.StateProvinceCode, this.PostalCode);
				}
			}
		}

		#endregion

		#endregion

		#region "Business Rules"

		protected override void AddBusinessRules()
		{
			ValidationRules.AddRule(CommonRules.StringRequired, new RuleArgs(Address1Property));
			ValidationRules.AddRule(CommonRules.StringMaxLength, new CommonRules.MaxLengthRuleArgs(Address1Property, 60));

			ValidationRules.AddRule(CommonRules.StringMaxLength, new CommonRules.MaxLengthRuleArgs(Address2Property, 60));

			ValidationRules.AddRule(CommonRules.StringRequired, new RuleArgs(CityProperty));
			ValidationRules.AddRule(CommonRules.StringMaxLength, new CommonRules.MaxLengthRuleArgs(CityProperty, 30));

			ValidationRules.AddRule(CommonRules.IntegerMinValue, new CommonRules.IntegerMinValueRuleArgs(StateProvinceIdProperty, 1));

			ValidationRules.AddRule(CommonRules.StringRequired, new RuleArgs(PostalCodeProperty));
			ValidationRules.AddRule(CommonRules.StringMaxLength, new CommonRules.MaxLengthRuleArgs(PostalCodeProperty, 15));

			ValidationRules.AddRule(CommonRules.IntegerMinValue, new CommonRules.IntegerMinValueRuleArgs(AddressTypeIdProperty, 1));
		}

		#endregion

		#region  "Factory Methods"

		internal static ContactAddress NewAddress(Int32 addressTypeId)
		{
			return DataPortal.CreateChild<ContactAddress>(addressTypeId);
		}

		internal static ContactAddress NewAddress(String address1, String address2, String city, Int32 stateProvinceId, String postalCode, Int32 addressTypeId)
		{
			return DataPortal.CreateChild<ContactAddress>(address1, address2, city, stateProvinceId, postalCode, addressTypeId);
		}

		internal static ContactAddress GetAddress(AddressBook.Business.Model.ContactAddress data)
		{
			return DataPortal.FetchChild<ContactAddress>(data);
		}

		private ContactAddress()
		{ /* require use of factory methods */ }

		#endregion

		#region "Data Access"

		protected override void Child_Create()
		{
			
		}

		private void Child_Create(Int32 addressTypeId)
		{
			using (BypassPropertyChecks)
			{
				this.AddressId = 0;
				this.Address1 = String.Empty;
				this.Address2 = String.Empty;
				this.City = String.Empty;
				this.StateProvinceId = 0;
				this.PostalCode = String.Empty;
				this.AddressTypeId = 0;
			}
		}

		private void Child_Create(String address1, String address2, String city, Int32 stateProvinceId, String postalCode, Int32 addressTypeId)
		{
			using (BypassPropertyChecks)
			{
				this.AddressId = 0;
				this.Address1 = address1;
				this.Address2 = address2;
				this.City = city;
				this.StateProvinceId = stateProvinceId;
				this.PostalCode = postalCode;
				this.AddressTypeId = addressTypeId;
			}
		}

		private void Child_Fetch(AddressBook.Business.Model.ContactAddress data)
		{
			using (BypassPropertyChecks)
			{
				this.AddressId = data.Address.Id;
				this.Address1 = data.Address.AddressLine1;
				this.Address2 = data.Address.AddressLine2;
				this.City = data.Address.City;
				this.StateProvinceId = data.Address.StateProvince.Id;
				this.PostalCode = data.Address.PostalCode;

				LoadProperty(ModifiedDateProperty, data.ModifiedDate);

				this.AddressTypeId = data.AddressTypeId;
				this.ContactId = data.ContactId;
			}
		}

		private void Child_Insert(Contact contact)
		{
			using (var ctx = ContextManager<AddressBook.Business.Model.AddressBookDataContext>.GetManager(AddressBook.Business.Model.Database.AddressBook))
			{
				// insert contact address data
				using (BypassPropertyChecks)
				{
					AddressBook.Business.Model.ContactAddress contactAddress = new AddressBook.Business.Model.ContactAddress();

					this.AddressId = Address.AddAddress(this.Address1,
																							this.Address2,
																							this.City,
																							this.StateProvinceId,
																							this.PostalCode);

					contactAddress.AddressId = this.AddressId;
					contactAddress.ContactId = contact.Id;
					contactAddress.AddressTypeId = this.AddressTypeId;
					contactAddress.ModifiedDate = System.DateTime.Now;
	
					ctx.DataContext.ContactAddresses.InsertOnSubmit(contactAddress);
					ctx.DataContext.SubmitChanges();
				}
			}
		}

		private void Child_Update()
		{
			using (var ctx = ContextManager<AddressBook.Business.Model.AddressBookDataContext>.GetManager(AddressBook.Business.Model.Database.AddressBook))
			{
				// update contact address data
				using (BypassPropertyChecks)
				{
					AddressBook.Business.Model.ContactAddress contactAddress = ctx.DataContext.ContactAddresses.First(ca => ca.AddressId == this.AddressId && ca.ContactId == this.ContactId);

					Address.UpdateAddress(this.AddressId,
																this.Address1,
																this.Address2,
																this.City,
																this.StateProvinceId,
																this.PostalCode);

					contactAddress.AddressId = this.AddressId;
					contactAddress.ContactId = this.ContactId;
					contactAddress.AddressTypeId = this.AddressTypeId;

					contactAddress.ModifiedDate = System.DateTime.Now;

					ctx.DataContext.SubmitChanges();
				}
			}
		}

		private void Child_DeleteSelf(Contact contact)
		{
			using (var ctx = ContextManager<AddressBook.Business.Model.AddressBookDataContext>.GetManager(AddressBook.Business.Model.Database.AddressBook))
			{
				int addressId = this.AddressId;
				AddressBook.Business.Model.ContactAddress contactAddress = ctx.DataContext.ContactAddresses.First(ca => ca.AddressId == this.AddressId && ca.ContactId == this.ContactId);

				ctx.DataContext.ContactAddresses.DeleteOnSubmit(contactAddress);
				ctx.DataContext.SubmitChanges();

				Address.RemoveAddress(addressId);
			}
		}

		#endregion
	}
}

